R provides several classes for representing time series objects for a variety of applications. Among those classes, ts is one of the main formats for time series data in R, mainly due to its simplicity and the wide adoption of this class by the main packages in R for time series analysis, for example, the forecast and stats packages.

The Natural Gas Consumption dataset

library(pacman)
p_load(Quandl)

ngc <- Quandl(code = "FRED/NATURALGAS",
              collapse = "quarterly",
              type = "ts",
              end_date = "2018-12-31")

class(ngc)

The simplest method to plot a ts object is with the plot function:

The attributes of the ts class

A regular time series is defined as an ordered sequence of observations over time, which is captured at equally spaced time intervals. Whenever this condition ceases to exist, the series becomes an irregular time series. The main characteristics of regular time series data is as follows:

A ts object is composed of two elements - the series values and its corresponding timestamp.

# number of observaitions
length(ngc)
[1] 76

We can look at the structure of a ts dataset with the head() function:

ngc
       Qtr1   Qtr2   Qtr3   Qtr4
2000 2050.6 1513.1 1475.0 2587.5
2001 2246.6 1444.4 1494.1 2120.2
2002 2258.4 1591.4 1542.2 2378.9
2003 2197.9 1368.4 1428.6 2263.7
2004 2100.9 1483.7 1482.2 2327.7
2005 2205.8 1534.1 1422.5 2326.4
2006 2126.4 1550.9 1462.1 2122.8
2007 2128.9 1555.2 1590.5 2399.2
2008 2278.2 1604.3 1460.9 2399.7
2009 2170.7 1527.8 1575.0 2491.9
2010 2142.9 1649.5 1637.5 2714.1
2011 2230.5 1657.3 1655.6 2541.9
2012 2127.8 1868.4 1807.2 2503.9
2013 2521.1 1742.9 1767.0 2920.8
2014 2557.9 1745.4 1809.3 2679.2
2015 2591.3 1899.9 1901.3 2588.2
2016 2356.3 2000.7 1947.8 2866.3
2017 2523.3 1910.4 1920.5 3086.0
2018 2796.7 2063.1 2156.1 2999.5

Here the rows represent the number of the cycle and the columns represent the cycle units. For the ngc data, each calendar year is a full cycle and the quarters are the cycle units.

The cycle() and the time() functions from the stats package provide the cycle units and the timestamp of each observation in the series:

cycle(ngc)
     Qtr1 Qtr2 Qtr3 Qtr4
2000    1    2    3    4
2001    1    2    3    4
2002    1    2    3    4
2003    1    2    3    4
2004    1    2    3    4
2005    1    2    3    4
2006    1    2    3    4
2007    1    2    3    4
2008    1    2    3    4
2009    1    2    3    4
2010    1    2    3    4
2011    1    2    3    4
2012    1    2    3    4
2013    1    2    3    4
2014    1    2    3    4
2015    1    2    3    4
2016    1    2    3    4
2017    1    2    3    4
2018    1    2    3    4
time(ngc)
        Qtr1    Qtr2    Qtr3    Qtr4
2000 2000.00 2000.25 2000.50 2000.75
2001 2001.00 2001.25 2001.50 2001.75
2002 2002.00 2002.25 2002.50 2002.75
2003 2003.00 2003.25 2003.50 2003.75
2004 2004.00 2004.25 2004.50 2004.75
2005 2005.00 2005.25 2005.50 2005.75
2006 2006.00 2006.25 2006.50 2006.75
2007 2007.00 2007.25 2007.50 2007.75
2008 2008.00 2008.25 2008.50 2008.75
2009 2009.00 2009.25 2009.50 2009.75
2010 2010.00 2010.25 2010.50 2010.75
2011 2011.00 2011.25 2011.50 2011.75
2012 2012.00 2012.25 2012.50 2012.75
2013 2013.00 2013.25 2013.50 2013.75
2014 2014.00 2014.25 2014.50 2014.75
2015 2015.00 2015.25 2015.50 2015.75
2016 2016.00 2016.25 2016.50 2016.75
2017 2017.00 2017.25 2017.50 2017.75
2018 2018.00 2018.25 2018.50 2018.75

A more concise way to get this information is with the frequency() and deltat() functions:

deltat(ngc)
[1] 0.25

Other useful functions are start() and end():

start(ngc)
[1] 2000    1
end(ngc)
[1] 2018    4

The ts_info() function from the TStudio package provides a concise summary of most of the functions above.

ts_info(ngc)
 The ngc series is a ts object with 1 variable and 76 observations
 Frequency: 4 
 Start time: 2000 1 
 End time: 2018 4 

Multivariate time series objects

When you have multivariate time series data, you need to use the mts (multiple time series) class. This combines the functionality of the ts and matrix classes.

ts_info(Coffee_Prices)
 The Coffee_Prices series is a mts object with 2 variables and 701 observations
 Frequency: 12 
 Start time: 1960 1 
 End time: 2018 5 

Creating a ts object

my_ts1 <- ts(data = 1:60,
             start = c(2010, 1),
             end = c(2014, 12),
             frequency = 12)

ts_info(my_ts1)
 The my_ts1 series is a ts object with 1 variable and 60 observations
 Frequency: 12 
 Start time: 2010 1 
 End time: 2014 12 
my_ts1
     Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2010   1   2   3   4   5   6   7   8   9  10  11  12
2011  13  14  15  16  17  18  19  20  21  22  23  24
2012  25  26  27  28  29  30  31  32  33  34  35  36
2013  37  38  39  40  41  42  43  44  45  46  47  48
2014  49  50  51  52  53  54  55  56  57  58  59  60

Now we will work through the typical process of converting data from a data.frame to a ts object.

str(US_indicators)
'data.frame':   528 obs. of  3 variables:
 $ Date             : Date, format: "1976-01-31" "1976-02-29" "1976-03-31" "1976-04-30" ...
 $ Vehicle Sales    : num  885 995 1244 1191 1203 ...
 $ Unemployment Rate: num  8.8 8.7 8.1 7.4 6.8 8 7.8 7.6 7.4 7.2 ...

For now, we will only convert the vehicle sales into a ts object.

Next, we need to define the start or end of the series. In this case, the series started in January 1976 so we can define it as start = c(1976, 1). Or we can write code to capture the starting point.

start_point
[1] 1976    1

Now we build the series:

One of the main limitations of the ts class is that it can only support two input elements for the timestamp. For example, when we converted tvs into a ts object, we lost the day component because ts could only store the month and year.

Creating an mts object

ts_info(US_indicators_ts)
 The US_indicators_ts series is a mts object with 2 variables and 528 observations
 Frequency: 12 
 Start time: 1976 1 
 End time: 2019 12 

Setting the series frequency

Setting the frequency of a series sets the length of a cycle.

\[ \text{Frequency} = \frac{\text{cycle length}}{\text{time interval between observation}} \]

In this example we will see how setting the frequency impacts the structure of the ts object output. First, we simulate close to ten years of daily data.

str(daily_df)
'data.frame':   3650 obs. of  2 variables:
 $ date: Date, format: "2010-01-01" "2010-01-02" "2010-01-03" "2010-01-04" ...
 $ y   : num  14 11.9 16.4 12.8 13.8 ...

Create ts object:

ts_info(days_week_ts)
 The days_week_ts series is a mts object with 2 variables and 3650 observations
 Frequency: 7 
 Start time: 1 6 
 End time: 523 1 

Data manipulation of ts objects

The window function

The main purpose of a window function is to subset a ts object based on a time range. The main argument of the window() function are the start and end arguments. Let’s use the window() function to extract all the observations of the year 2005 from the NGC series:

window(ngc, start = c(2005, 1), end = c(2005, 4))
       Qtr1   Qtr2   Qtr3   Qtr4
2005 2205.8 1534.1 1422.5 2326.4

We can also extract a specific frequency unit from the series. Say we’re interested in extracting all the observations of the series that occurred in the third quarter of the year. This can be done by setting the starting point at the third quarter of the first year and the frequency to 1.

window(ngc, start = c(2000, 3), frequency = 1)
Time Series:
Start = 2000.5 
End = 2018.5 
Frequency = 1 
 [1] 1475.0 1494.1 1542.2 1428.6 1482.2 1422.5 1462.1 1590.5 1460.9 1575.0 1637.5 1655.6 1807.2 1767.0 1809.3 1901.3 1947.8 1920.5 2156.1

Aggregating ts objects

The aggregate() function splits the data into subsets, computes specific summary statistics, and then aggregates the results to a ts or data.frame object. Let’s use aggregate() to transform the NGC series from a quarterly frequency to yearly:

1+1
[1] 2

Creating lags and leads for ts objects

The lag() function from the stats package (this should not be confused with the lag() function from the dplyr package) can be used to create lags or leads for ts objects.

ts_info(ngc_lag4)
 The ngc_lag4 series is a ts object with 1 variable and 76 observations
 Frequency: 4 
 Start time: 2001 1 
 End time: 2019 4 

Visualizing ts and mts objects

The plot.ts() function

Plotting a ts object:

Plotting an mts object:

The dygraphs package

The dygraphs package is an R interface to the dygraphs JavaScript charting library.

For the US_indicators_ts series, we will add a second y-axis, which allows us to plot and compare the two series that are not on the same scale:

The TSstudio package

ts_plot(tvs_ts,
        title = "US Monthly Total Vehicle Sales",
        Ytitle = "Thousands of Vehicle",
        slider = TRUE)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     

We can add an interactive slider for the x-axis.

LS0tCnRpdGxlOiAiQ2hhcHRlciAyOiBUaGUgVGltZSBTZXJpZXMgT2JqZWN0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpSIHByb3ZpZGVzIHNldmVyYWwgY2xhc3NlcyBmb3IgcmVwcmVzZW50aW5nIHRpbWUgc2VyaWVzIG9iamVjdHMgZm9yIGEgdmFyaWV0eSBvZiBhcHBsaWNhdGlvbnMuIEFtb25nIHRob3NlIGNsYXNzZXMsIGB0c2AgaXMgb25lIG9mIHRoZSBtYWluIGZvcm1hdHMgZm9yIHRpbWUgc2VyaWVzIGRhdGEgaW4gUiwgbWFpbmx5IGR1ZSB0byBpdHMgc2ltcGxpY2l0eSBhbmQgdGhlIHdpZGUgYWRvcHRpb24gb2YgdGhpcyBjbGFzcyBieSB0aGUgbWFpbiBwYWNrYWdlcyBpbiBSIGZvciB0aW1lIHNlcmllcyBhbmFseXNpcywgZm9yIGV4YW1wbGUsIHRoZSBgZm9yZWNhc3RgIGFuZCBgc3RhdHNgIHBhY2thZ2VzLgoKIyBUaGUgTmF0dXJhbCBHYXMgQ29uc3VtcHRpb24gZGF0YXNldAoKYGBge3J9CmxpYnJhcnkocGFjbWFuKQpwX2xvYWQoUXVhbmRsKQoKbmdjIDwtIFF1YW5kbChjb2RlID0gIkZSRUQvTkFUVVJBTEdBUyIsCiAgICAgICAgICAgICAgY29sbGFwc2UgPSAicXVhcnRlcmx5IiwKICAgICAgICAgICAgICB0eXBlID0gInRzIiwKICAgICAgICAgICAgICBlbmRfZGF0ZSA9ICIyMDE4LTEyLTMxIikKCmNsYXNzKG5nYykKYGBgCgpUaGUgc2ltcGxlc3QgbWV0aG9kIHRvIHBsb3QgYSBgdHNgIG9iamVjdCBpcyB3aXRoIHRoZSBgcGxvdGAgZnVuY3Rpb246CgpgYGB7cn0KcGxvdC50cyhuZ2MsCiAgICAgICAgbWFpbiA9ICJVUyBRdWFydGVybHkgTmF0dXJhbCBHYXMgQ29uc3VtcHRpb24iLAogICAgICAgIHlsYWIgPSAiQmlsbGlvbiBvZiBDdWJpYyBGZWV0IikKYGBgCgojIFRoZSBhdHRyaWJ1dGVzIG9mIHRoZSBgdHNgIGNsYXNzCgpBIHJlZ3VsYXIgdGltZSBzZXJpZXMgaXMgZGVmaW5lZCBhcyBhbiBvcmRlcmVkIHNlcXVlbmNlIG9mIG9ic2VydmF0aW9ucyBvdmVyIHRpbWUsIHdoaWNoIGlzIGNhcHR1cmVkIGF0IGVxdWFsbHkgc3BhY2VkIHRpbWUgaW50ZXJ2YWxzLiBXaGVuZXZlciB0aGlzIGNvbmRpdGlvbiBjZWFzZXMgdG8gZXhpc3QsIHRoZSBzZXJpZXMgYmVjb21lcyBhbiBpcnJlZ3VsYXIgdGltZSBzZXJpZXMuIFRoZSBtYWluIGNoYXJhY3RlcmlzdGljcyBvZiByZWd1bGFyIHRpbWUgc2VyaWVzIGRhdGEgaXMgYXMgZm9sbG93czoKCi0gICBDeWNsZS9wZXJpb2Q6IGEgcmVndWxhciB1bml0IG9mIHRpbWUgdGhhdCBzcGxpdCB0aGUgc2VyaWVzIGludG8gY29uc2VjdXRpdmUgYW5kIGVxdWFsbHkgbG9uZyBzdWJzZXRzCgotICAgZnJlcXVlbmN5OiBkZWZpbmVzIHRoZSBsZW5ndGggb3IgdGhlIG51bWJlciBvZiB1bml0cyBvZiB0aGUgY3ljbGUKCi0gICB0aW1lc3RhbXA6IHByb3ZpZGVzIHRoZSB0aW1lIGVhY2ggb2JzZXJ2YXRpb24gaW4gdGhlIHNlcmllcyB3YXMgY2FwdHVyZWQsIGFuZCBjYW4gYmUgdXNlZCBhcyB0aGUgc2VyaWVzIGluZGV4LgoKQSBgdHNgIG9iamVjdCBpcyBjb21wb3NlZCBvZiB0d28gZWxlbWVudHMgLSB0aGUgc2VyaWVzIHZhbHVlcyBhbmQgaXRzIGNvcnJlc3BvbmRpbmcgdGltZXN0YW1wLgoKYGBge3J9CiMgbnVtYmVyIG9mIG9ic2VydmFpdGlvbnMKbGVuZ3RoKG5nYykKYGBgCgpXZSBjYW4gbG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIGEgYHRzYCBkYXRhc2V0IHdpdGggdGhlIGBoZWFkKClgIGZ1bmN0aW9uOgoKYGBge3J9Cm5nYwpgYGAKCkhlcmUgdGhlIHJvd3MgcmVwcmVzZW50IHRoZSBudW1iZXIgb2YgdGhlIGN5Y2xlIGFuZCB0aGUgY29sdW1ucyByZXByZXNlbnQgdGhlIGN5Y2xlIHVuaXRzLiBGb3IgdGhlIGBuZ2NgIGRhdGEsIGVhY2ggY2FsZW5kYXIgeWVhciBpcyBhIGZ1bGwgY3ljbGUgYW5kIHRoZSBxdWFydGVycyBhcmUgdGhlIGN5Y2xlIHVuaXRzLgoKVGhlIGBjeWNsZSgpYCBhbmQgdGhlIGB0aW1lKClgIGZ1bmN0aW9ucyBmcm9tIHRoZSAqKnN0YXRzKiogcGFja2FnZSBwcm92aWRlIHRoZSBjeWNsZSB1bml0cyBhbmQgdGhlIHRpbWVzdGFtcCBvZiBlYWNoIG9ic2VydmF0aW9uIGluIHRoZSBzZXJpZXM6CgpgYGB7cn0KY3ljbGUobmdjKQoKdGltZShuZ2MpCmBgYAoKQSBtb3JlIGNvbmNpc2Ugd2F5IHRvIGdldCB0aGlzIGluZm9ybWF0aW9uIGlzIHdpdGggdGhlIGBmcmVxdWVuY3koKWAgYW5kIGBkZWx0YXQoKWAgZnVuY3Rpb25zOgoKYGBge3J9CmZyZXF1ZW5jeShuZ2MpCgpkZWx0YXQobmdjKQpgYGAKCk90aGVyIHVzZWZ1bCBmdW5jdGlvbnMgYXJlIGBzdGFydCgpYCBhbmQgYGVuZCgpYDoKCmBgYHtyfQpzdGFydChuZ2MpCgplbmQobmdjKQpgYGAKClRoZSBgdHNfaW5mbygpYCBmdW5jdGlvbiBmcm9tIHRoZSAqKlRTdHVkaW8qKiBwYWNrYWdlIHByb3ZpZGVzIGEgY29uY2lzZSBzdW1tYXJ5IG9mIG1vc3Qgb2YgdGhlIGZ1bmN0aW9ucyBhYm92ZS4KCmBgYHtyfQpwX2xvYWQoVFNzdHVkaW8pCgp0c19pbmZvKG5nYykKYGBgCgojIyBNdWx0aXZhcmlhdGUgdGltZSBzZXJpZXMgb2JqZWN0cwoKV2hlbiB5b3UgaGF2ZSBtdWx0aXZhcmlhdGUgdGltZSBzZXJpZXMgZGF0YSwgeW91IG5lZWQgdG8gdXNlIHRoZSBgbXRzYCAobXVsdGlwbGUgdGltZSBzZXJpZXMpIGNsYXNzLiBUaGlzIGNvbWJpbmVzIHRoZSBmdW5jdGlvbmFsaXR5IG9mIHRoZSBgdHNgIGFuZCBgbWF0cml4YCBjbGFzc2VzLgoKYGBge3J9CmRhdGEoIkNvZmZlZV9QcmljZXMiKQpoZWFkKENvZmZlZV9QcmljZXMpCgp0c19pbmZvKENvZmZlZV9QcmljZXMpCmBgYAoKIyMgQ3JlYXRpbmcgYSBgdHNgIG9iamVjdAoKYGBge3J9Cm15X3RzMSA8LSB0cyhkYXRhID0gMTo2MCwKICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDEwLCAxKSwKICAgICAgICAgICAgIGVuZCA9IGMoMjAxNCwgMTIpLAogICAgICAgICAgICAgZnJlcXVlbmN5ID0gMTIpCgp0c19pbmZvKG15X3RzMSkKCm15X3RzMQpgYGAKCk5vdyB3ZSB3aWxsIHdvcmsgdGhyb3VnaCB0aGUgdHlwaWNhbCBwcm9jZXNzIG9mIGNvbnZlcnRpbmcgZGF0YSBmcm9tIGEgYGRhdGEuZnJhbWVgIHRvIGEgYHRzYCBvYmplY3QuCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCgojIGxvYWQgdGhlIGRhdGEKZGF0YSgiVVNfaW5kaWNhdG9ycyIpCnN0cihVU19pbmRpY2F0b3JzKQpgYGAKCkZvciBub3csIHdlIHdpbGwgb25seSBjb252ZXJ0IHRoZSB2ZWhpY2xlIHNhbGVzIGludG8gYSBgdHNgIG9iamVjdC4KCmBgYHtyfQp0dnMgPC0gCiAgVVNfaW5kaWNhdG9ycyAlPiUgCiAgc2VsZWN0KERhdGUsIGBWZWhpY2xlIFNhbGVzYCkgJT4lIAogIGFycmFuZ2UoRGF0ZSkKCmhlYWQodHZzKQpgYGAKCk5leHQsIHdlIG5lZWQgdG8gZGVmaW5lIHRoZSBzdGFydCBvciBlbmQgb2YgdGhlIHNlcmllcy4gSW4gdGhpcyBjYXNlLCB0aGUgc2VyaWVzIHN0YXJ0ZWQgaW4gSmFudWFyeSAxOTc2IHNvIHdlIGNhbiBkZWZpbmUgaXQgYXMgYHN0YXJ0ID0gYygxOTc2LCAxKWAuIE9yIHdlIGNhbiB3cml0ZSBjb2RlIHRvIGNhcHR1cmUgdGhlIHN0YXJ0aW5nIHBvaW50LgoKYGBge3J9CmxpYnJhcnkobHVicmlkYXRlKQoKc3RhcnRfcG9pbnQgPC0gYyh5ZWFyKG1pbih0dnMkRGF0ZSkpLCBtb250aChtaW4odHZzJERhdGUpKSkKc3RhcnRfcG9pbnQKYGBgCgpOb3cgd2UgYnVpbGQgdGhlIHNlcmllczoKCmBgYHtyfQp0dnNfdHMgPC0gdHMoZGF0YSA9IHR2cyRgVmVoaWNsZSBTYWxlc2AsCiAgICAgICAgICAgICBzdGFydCA9IHN0YXJ0X3BvaW50LAogICAgICAgICAgICAgZnJlcXVlbmN5ID0gMTIpCmBgYAoKT25lIG9mIHRoZSBtYWluIGxpbWl0YXRpb25zIG9mIHRoZSBgdHNgIGNsYXNzIGlzIHRoYXQgaXQgY2FuIG9ubHkgc3VwcG9ydCB0d28gaW5wdXQgZWxlbWVudHMgZm9yIHRoZSB0aW1lc3RhbXAuIEZvciBleGFtcGxlLCB3aGVuIHdlIGNvbnZlcnRlZCBgdHZzYCBpbnRvIGEgYHRzYCBvYmplY3QsIHdlIGxvc3QgdGhlIGRheSBjb21wb25lbnQgYmVjYXVzZSBgdHNgIGNvdWxkIG9ubHkgc3RvcmUgdGhlIG1vbnRoIGFuZCB5ZWFyLgoKIyMgQ3JlYXRpbmcgYW4gYG10c2Agb2JqZWN0CgpgYGB7cn0KVVNfaW5kaWNhdG9ycyA8LSBhcnJhbmdlKFVTX2luZGljYXRvcnMsIERhdGUpCgpVU19pbmRpY2F0b3JzX3RzIDwtIHRzKGRhdGEgPSBzZWxlY3QoVVNfaW5kaWNhdG9ycywgYFZlaGljbGUgU2FsZXNgLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBVbmVtcGxveW1lbnQgUmF0ZWApLAogICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYyh5ZWFyKG1pbih0dnMkRGF0ZSkpLCBtb250aChtaW4odHZzJERhdGUpKSksCiAgICAgICAgICAgICAgICAgICAgICAgZnJlcXVlbmN5ID0gMTIpCgp0c19pbmZvKFVTX2luZGljYXRvcnNfdHMpCmBgYAoKIyMgU2V0dGluZyB0aGUgc2VyaWVzIGZyZXF1ZW5jeQoKU2V0dGluZyB0aGUgZnJlcXVlbmN5IG9mIGEgc2VyaWVzIHNldHMgdGhlIGxlbmd0aCBvZiBhIGN5Y2xlLgoKJCQKXHRleHR7RnJlcXVlbmN5fSA9IFxmcmFje1x0ZXh0e2N5Y2xlIGxlbmd0aH19e1x0ZXh0e3RpbWUgaW50ZXJ2YWwgYmV0d2VlbiBvYnNlcnZhdGlvbn19CiQkCgpJbiB0aGlzIGV4YW1wbGUgd2Ugd2lsbCBzZWUgaG93IHNldHRpbmcgdGhlIGZyZXF1ZW5jeSBpbXBhY3RzIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGB0c2Agb2JqZWN0IG91dHB1dC4gRmlyc3QsIHdlIHNpbXVsYXRlIGNsb3NlIHRvIHRlbiB5ZWFycyBvZiBkYWlseSBkYXRhLgoKYGBge3J9CmRhaWx5X2RmIDwtIGRhdGEuZnJhbWUoZGF0ZSA9IHNlcS5EYXRlKGZyb20gPSBhcy5EYXRlKCIyMDEwLTAxLTAxIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSAzNjUgKiAxMCwgYnkgPSAiZGF5IiksCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJub3JtKDM2NSAqIDEwLCBtZWFuID0gMTUsIHNkID0gMikpCgpzdHIoZGFpbHlfZGYpCmBgYAoKQ3JlYXRlIGB0c2Agb2JqZWN0OgoKYGBge3J9CmRheXNfd2Vla190cyA8LSB0cyhkYWlseV9kZiwKICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygxLCB3ZGF5KG1pbihkYWlseV9kZiRkYXRlKSkpLAogICAgICAgICAgICAgICAgICAgZnJlcXVlbmN5ID0gNykKCnRzX2luZm8oZGF5c193ZWVrX3RzKQpgYGAKCiMgRGF0YSBtYW5pcHVsYXRpb24gb2YgYHRzYCBvYmplY3RzCgojIyBUaGUgd2luZG93IGZ1bmN0aW9uCgpUaGUgbWFpbiBwdXJwb3NlIG9mIGEgd2luZG93IGZ1bmN0aW9uIGlzIHRvIHN1YnNldCBhIGB0c2Agb2JqZWN0IGJhc2VkIG9uIGEgdGltZSByYW5nZS4gVGhlIG1haW4gYXJndW1lbnQgb2YgdGhlIGB3aW5kb3coKWAgZnVuY3Rpb24gYXJlIHRoZSBgc3RhcnRgIGFuZCBgZW5kYCBhcmd1bWVudHMuIExldCdzIHVzZSB0aGUgYHdpbmRvdygpYCBmdW5jdGlvbiB0byBleHRyYWN0IGFsbCB0aGUgb2JzZXJ2YXRpb25zIG9mIHRoZSB5ZWFyIDIwMDUgZnJvbSB0aGUgTkdDIHNlcmllczoKCmBgYHtyfQp3aW5kb3cobmdjLCBzdGFydCA9IGMoMjAwNSwgMSksIGVuZCA9IGMoMjAwNSwgNCkpCmBgYAoKV2UgY2FuIGFsc28gZXh0cmFjdCBhIHNwZWNpZmljIGZyZXF1ZW5jeSB1bml0IGZyb20gdGhlIHNlcmllcy4gU2F5IHdlJ3JlIGludGVyZXN0ZWQgaW4gZXh0cmFjdGluZyBhbGwgdGhlIG9ic2VydmF0aW9ucyBvZiB0aGUgc2VyaWVzIHRoYXQgb2NjdXJyZWQgaW4gdGhlIHRoaXJkIHF1YXJ0ZXIgb2YgdGhlIHllYXIuIFRoaXMgY2FuIGJlIGRvbmUgYnkgc2V0dGluZyB0aGUgc3RhcnRpbmcgcG9pbnQgYXQgdGhlIHRoaXJkIHF1YXJ0ZXIgb2YgdGhlIGZpcnN0IHllYXIgYW5kIHRoZSBgZnJlcXVlbmN5YCB0byAxLgoKYGBge3J9CndpbmRvdyhuZ2MsIHN0YXJ0ID0gYygyMDAwLCAzKSwgZnJlcXVlbmN5ID0gMSkKYGBgCgojIyBBZ2dyZWdhdGluZyBgdHNgIG9iamVjdHMKClRoZSBgYWdncmVnYXRlKClgIGZ1bmN0aW9uIHNwbGl0cyB0aGUgZGF0YSBpbnRvIHN1YnNldHMsIGNvbXB1dGVzIHNwZWNpZmljIHN1bW1hcnkgc3RhdGlzdGljcywgYW5kIHRoZW4gYWdncmVnYXRlcyB0aGUgcmVzdWx0cyB0byBhIGB0c2Agb3IgYGRhdGEuZnJhbWVgIG9iamVjdC4gTGV0J3MgdXNlIGBhZ2dyZWdhdGUoKWAgdG8gdHJhbnNmb3JtIHRoZSBOR0Mgc2VyaWVzIGZyb20gYSBxdWFydGVybHkgZnJlcXVlbmN5IHRvIHllYXJseToKCmBgYHtyfQpuZ2NfeWVhcmx5IDwtIGFnZ3JlZ2F0ZShuZ2MsIG5mcmVxdWVuY3kgPSAxLCBGVU4gPSAic3VtIikKbmdjX3llYXJseQpgYGAKCiMjIENyZWF0aW5nIGxhZ3MgYW5kIGxlYWRzIGZvciBgdHNgIG9iamVjdHMKClRoZSBgbGFnKClgIGZ1bmN0aW9uIGZyb20gdGhlICoqc3RhdHMqKiBwYWNrYWdlICh0aGlzIHNob3VsZCBub3QgYmUgY29uZnVzZWQgd2l0aCB0aGUgYGxhZygpYCBmdW5jdGlvbiBmcm9tIHRoZSAqKmRwbHlyKiogcGFja2FnZSkgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGxhZ3Mgb3IgbGVhZHMgZm9yIGB0c2Agb2JqZWN0cy4KCmBgYHtyfQpuZ2NfbGFnNCA8LSBzdGF0czo6bGFnKG5nYywgayA9IC00KQoKdHNfaW5mbyhuZ2NfbGFnNCkKYGBgCgojIFZpc3VhbGl6aW5nIGB0c2AgYW5kIGBtdHNgIG9iamVjdHMKCiMjIFRoZSBgcGxvdC50cygpYCBmdW5jdGlvbgoKUGxvdHRpbmcgYSBgdHNgIG9iamVjdDoKCmBgYHtyfQpwbG90LnRzKHR2c190cywKICAgICAgICBtYWluID0gIlVTIE1vbnRobHkgVG90YWwgVmVoaWNsZSBTYWxlcyIsCiAgICAgICAgeWxhYiA9ICJUaG91c2FuZHMgb2YgVmVoaWNsZSIsCiAgICAgICAgeGxhYiA9ICJUaW1lIikKYGBgCgpQbG90dGluZyBhbiBgbXRzYCBvYmplY3Q6CgpgYGB7cn0KcGxvdC50cyhVU19pbmRpY2F0b3JzX3RzLAogICAgICAgIHBsb3QudHlwZSA9ICJtdWx0aXBsZSIsCiAgICAgICAgbWFpbiA9ICJVUyBNb250aGx5IFZlaGljbGUgU2FsZXMgdnMuIFVuZW1wbG95bWVudCBSYXRlIiwKICAgICAgICB4bGFiID0gIlRpbWUiKQpgYGAKCiMjIFRoZSAqKmR5Z3JhcGhzKiogcGFja2FnZQoKVGhlICoqZHlncmFwaHMqKiBwYWNrYWdlIGlzIGFuIFIgaW50ZXJmYWNlIHRvIHRoZSBgZHlncmFwaHNgIEphdmFTY3JpcHQgY2hhcnRpbmcgbGlicmFyeS4KCmBgYHtyfQpwX2xvYWQoZHlncmFwaHMpCgpkeWdyYXBoKHR2c190cywKICAgICAgICBtYWluID0gIlVTIE1vbnRobHkgVG90YWwgVmVoaWNsZSBTYWxlcyIsCiAgICAgICAgeWxhYiA9ICJUaG91c2FuZHMgb2YgVmVoaWNsZSIpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoKQpgYGAKCkZvciB0aGUgYFVTX2luZGljYXRvcnNfdHNgIHNlcmllcywgd2Ugd2lsbCBhZGQgYSBzZWNvbmQgKnkqLWF4aXMsIHdoaWNoIGFsbG93cyB1cyB0byBwbG90IGFuZCBjb21wYXJlIHRoZSB0d28gc2VyaWVzIHRoYXQgYXJlIG5vdCBvbiB0aGUgc2FtZSBzY2FsZToKCmBgYHtyfQpkeWdyYXBoKFVTX2luZGljYXRvcnNfdHMsCiAgICAgICAgbWFpbiA9ICJVUyBNb250aGx5IFZlaGljbGUgU2FsZXMgdnMuIFVuZW1wbG95bWVudCBSYXRlIikgJT4lIAogIGR5QXhpcygieSIsIGxhYmVsID0gIlZlaGljbGUgU2FsZXMiKSAlPiUgCiAgZHlBeGlzKCJ5MiIsIGxhYmVsID0gIlVuZW1wbG95bWVudCBSYXRlIikgJT4lIAogIGR5U2VyaWVzKCJWZWhpY2xlIFNhbGVzIiwgYXhpcyA9ICJ5IiwgY29sb3IgPSAiZ3JlZW4iKSAlPiUgCiAgZHlTZXJpZXMoIlVuZW1wbG95bWVudCBSYXRlIiwgYXhpcyA9ICJ5MiIsIGNvbG9yID0gInJlZCIpICU+JSAKICBkeUxlZ2VuZCh3aWR0aCA9IDQwMCkKYGBgCgojIyBUaGUgVFNzdHVkaW8gcGFja2FnZQoKYGBge3J9CnBfbG9hZChUU3N0dWRpbykKCnRzX3Bsb3QodHZzX3RzLAogICAgICAgIHRpdGxlID0gIlVTIE1vbnRobHkgVG90YWwgVmVoaWNsZSBTYWxlcyIsCiAgICAgICAgWXRpdGxlID0gIlRob3VzYW5kcyBvZiBWZWhpY2xlIiwKICAgICAgICBzbGlkZXIgPSBUUlVFKQpgYGAKCldlIGNhbiBhZGQgYW4gaW50ZXJhY3RpdmUgc2xpZGVyIGZvciB0aGUgKngqLWF4aXMuCgpgYGB7cn0KdHNfcGxvdChVU19pbmRpY2F0b3JzX3RzLAogICAgICAgIHRpdGxlID0gIlVTIE1vbnRobHkgVmVoaWNsZSBTYWxlcyB2cy4gVW5lbXBsb3ltZW50IFJhdGUiLAogICAgICAgIHR5cGUgPSAibXVsdGlwbGUiKQpgYGAK